#pragma once

#include <iostream>
#include <fstream>
#include <cstring>
#include <map>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/dnn/dnn.hpp>
#include <queue>
#include "acl/acl.h"
#include "det_data_type.h"

typedef __fp16 float16_t;

struct Yolov5AscendDetConfigs
{
    std::string omPath;
    int classNum;    
    cv::Size inputSize = cv::Size(640, 640);
    float scoreThr = 0.25;
    float nmsThr = 0.5;
    std::array<float, 3> means = {0.0f, 0.0f, 0.0f};
    std::array<float, 3> norms = {1.0f, 1.0f, 1.0f};
    std::vector<std::vector<int>> anchors = {
        {10, 13, 16, 30, 33, 23},
        {30, 61, 62, 45, 59, 119},
        {116, 90, 156, 198, 373, 326}
    };
    int deviceId = 0;
};


class Yolov5Ascend
{
public:
    Yolov5Ascend(const Yolov5AscendDetConfigs& config);
    ~Yolov5Ascend();
    void detect(cv::Mat& img, std::vector<DetectionTarget>& objects);
    void drawObject(cv::Mat& img, const std::vector<DetectionTarget>& objects,
        const std::vector<std::string>& labels={});

private:
    void init();
    bool initResource();
    bool loadModelFromFile(const char *modelPath);
    bool createDesc();
    void createModelOutput();
    void createModelInput();
    void unloadModel();
    void unloadPicture();
    void destroyResource();
    cv::Mat preProcess(cv::Mat& src, int interpolation=cv::INTER_LINEAR);
    void postProcess(std::vector<DetectionTarget>& objects, const cv::Size& imgSize);

private:
    uint32_t modelId;
    aclmdlDesc *modelDesc;
    aclmdlDataset *inputDataSet;
    aclDataBuffer *inputDataBuffer;
    aclmdlDataset *outputDataSet;
    aclDataBuffer *outputDataBuffer;
    void *pictureDeviceData;    
    void *outputDeviceData;
    size_t pictureDataSize ;
    size_t outputDataSize;
    Yolov5AscendDetConfigs ascendCfg;
};
